feat(chain): implement the state transition function - #30
Merged
Conversation
Transcribe leanSpec's state transition into verity-chain: genesis generation, slot advancement, header validation, and the 3SF-mini justification and finalization accounting over a block's attestations. Signatures are verified before the transition runs, so this stays a pure function over verity-types with no cryptographic dependency. The one dependency it does add is libssz-merkle: the transition commits to hash_tree_root of the state, the parent header, and the block body, and that commitment cannot be expressed without it. No capability-contract trait is introduced. There is one implementation, and the kickoff rule is to split only when a second one earns it; the error type is the plain enum ARCHITECTURE.md's contract calls for, carrying the thirteen leanSpec rejection reasons the vectors reach. process_slots additionally guards its empty-slot walk against a gap larger than HISTORICAL_ROOTS_LIMIT. leanSpec places that guard in fork choice, immediately before it calls the transition; putting it at the transition's own entry makes the loop bounded by this function's signature rather than by its caller. The threshold is leanSpec's. 73 of the 74 state-transition vectors are consumed. The remaining one records a rejection raised while the generator was building its block, so it ships with an empty block list and cannot be replayed by any client; the rule it covers is unit-tested on proposer_for_slot instead.
Clarify the attestation vote accumulator name and align comments. Reuse advance_checkpoint from the justification module instead of inlining the slot comparison.
Make the header-stage checkpoint derivation function name describe its purpose explicitly.
Make the distinct AttestationData counter name describe what it holds.
Use a more direct predicate name for the chain-membership check.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The state transition, transcribed from leanSpec. This is the first code in the tree that decides whether a block is valid.
What lands
state_transition—process_slots→process_block_header→process_attestations, then the post-state-root commitment. Plusgenerate_genesisandproposer_for_slot.process_attestationsis the bulk of it: the 3SF-mini accounting. The state stores votes as one flat bitlist segmented by tracked root, so the module unpacks that layout into a per-root tally, applies the block's votes under five filters, and packs it back. Roots are held in aBTreeMap, which is what makes the repack canonical without a sort.No cryptography. leanSpec is explicit that signatures are verified before the transition is called, so
verity-chainstill depends on nothing butverity-types— pluslibssz-merkle, because the transition commits tohash_tree_rootof the state, the parent header, and the block body, and that commitment cannot be written without it.No capability-contract trait.
ARCHITECTURE.mdleaves the crate placement to implementation time. There is one implementation and the kickoff rule is to split only when a second earns it, sostate_transitionis a free function andRejectionReasonis the plain enum the contract describes — thirteen leanSpec reasons, the ones the vectors reach, named verbatim so the two stay greppable against each other.One deliberate deviation
process_slotsguards its empty-slot walk against a gap larger thanHISTORICAL_ROOTS_LIMITand returnsBLOCK_SLOT_GAP_TOO_LARGE. leanSpec raises that same reason with that same threshold, but from fork choice, immediately before it calls the transition. Moving it to the transition's own entry is what makes the loop bounded by this function's signature instead of by its caller. No vector changes behaviour.